package jastgen.generator;

import java.io.PrintWriter;

public class UtilBodyGenerator implements BodyGenerator {

	@Override
	public void generate(final PrintWriter out) {

		out.println("public final class Util {");
		out.println();
		out.println("	public static final int");
		out.println("	LT = -1,");
		out.println("	EQ =  0,");
		out.println("	GT =  1;");
		out.println();
		out.println("	// This method is removable safely.");
		out.println("	public static boolean isLT(");
		out.println("			final int cmp)");
		out.println("	{");
		out.println("		return cmp < 0;");
		out.println("	}");
		out.println();
		out.println("	// This method is removable safely.");
		out.println("	public static boolean isGT(");
		out.println("			final int cmp)");
		out.println("	{");
		out.println("		return cmp > 0;");
		out.println("	}");
		out.println();
		out.println("	public static boolean eq(");
		out.println("			final int lhs,");
		out.println("			final int rhs)");
		out.println("	{");
		out.println("		return lhs == rhs;");
		out.println("	}");
		out.println();
		out.println("	public static <T> boolean eq(");
		out.println("			final T lhs,");
		out.println("			final T rhs)");
		out.println("	{");
		out.println("		return (lhs == null) ? (rhs == null) : lhs.equals(rhs);");
		out.println("	}");
		out.println();
		out.println("	public static int hash(");
		out.println("			final Object x)");
		out.println("	{");
		out.println("		return (x == null) ? 0 : x.hashCode();");
		out.println("	}");
		out.println();
		out.println("	// TODO: cmpのプリミティブ版を書く (使用している)");
		out.println();
		out.println("	public static int cmp(");
		out.println("			final Object lhs,");
		out.println("			final Object rhs)");
		out.println("	{");
		out.println("		if((lhs instanceof Comparable<?>) && (rhs instanceof Comparable<?>))");
		out.println("			return cmp((Comparable)lhs, (Comparable)rhs);");
		out.println("		if((lhs instanceof Iterable<?>) && rhs instanceof Iterable<?>)");
		out.println("			return cmp((Iterable)lhs, (Iterable)rhs);");
		out.println("		throw new IllegalStateException(");
		out.println("				\"Compared non-Comparable objects. (\"");
		out.println("				+ \"lhs(\" + lhs + \"), \"");
		out.println("				+ \"rhs(\" + rhs + \"))\");");
		out.println("	}");
		out.println();
		out.println("	// compareToはnullに対してはNullPointerExceptionを投げるのが普通?");
		out.println("	public static <T extends Comparable<T>> int cmp(");
		out.println("			final T lhs,");
		out.println("			final T rhs)");
		out.println("	{");
		out.println("		if(lhs == null) {");
		out.println("			if(rhs == null)");
		out.println("				return EQ;");
		out.println("			return LT;");
		out.println("		}");
		out.println("		if(rhs == null)");
		out.println("			return GT;");
		out.println("		return lhs.compareTo(rhs);");
		out.println("	}");
		out.println();
		out.println("	public static <T extends Comparable<T>> int cmp(");
		out.println("			final Iterable<T> lhs,");
		out.println("			final Iterable<T> rhs)");
		out.println("	{");
		out.println("		// nullまたは非nullの比較");
		out.println("		if(lhs == null) {");
		out.println("			if(rhs == null)");
		out.println("				return EQ;");
		out.println("			return LT;");
		out.println("		}");
		out.println("		if(rhs == null)");
		out.println("			return GT;");
		out.println();
		out.println("		final Iterator<T> itL = lhs.iterator();");
		out.println("		final Iterator<T> itR = rhs.iterator();");
		out.println("		while(true) {");
		out.println("			// 要素数の比較");
		out.println("			if(!itL.hasNext()) {");
		out.println("				if(!itR.hasNext())");
		out.println("					return EQ;");
		out.println("				return LT;");
		out.println("			}");
		out.println("			if(!itR.hasNext())");
		out.println("				return GT;");
		out.println();
		out.println("			// 要素の比較");
		out.println("			final int cmp = cmp(itL.next(), itR.next());");
		out.println("			if(cmp != EQ)");
		out.println("				return cmp;");
		out.println("		}");
		out.println("	}");
		out.println();
		out.println("	public static <T> Collection<T> unmodifiableCollection(");
		out.println("			final Collection<? extends T> c)");
		out.println("	{");
		out.println("		if(c == null)");
		out.println("			return null;");
		out.println("		return Collections.unmodifiableCollection(c);");
		out.println("	}");
		out.println();
		out.println("	public static <T> List<T> unmodifiableList(");
		out.println("			final List<? extends T> l)");
		out.println("	{");
		out.println("		if(l == null)");
		out.println("			return null;");
		out.println("		return Collections.unmodifiableList(l);");
		out.println("	}");
		out.println();
		out.println("	public static <K, V> Map<K, V> unmodifiableMap(");
		out.println("			final Map<? extends K, ? extends V> m)");
		out.println("	{");
		out.println("		if(m == null)");
		out.println("			return null;");
		out.println("		return Collections.unmodifiableMap(m);");
		out.println("	}");
		out.println();
		out.println("	public static <T> Set<T> unmodifiableSet(");
		out.println("			final Set<? extends T> s)");
		out.println("	{");
		out.println("		if(s == null)");
		out.println("			return null;");
		out.println("		return Collections.unmodifiableSet(s);");
		out.println("	}");
		out.println();
		out.println("	public static <K, V> SortedMap<K, V> unmodifiableSortedMap(");
		out.println("			final SortedMap<K, ? extends V> m)");
		out.println("	{");
		out.println("		if(m == null)");
		out.println("			return null;");
		out.println("		return Collections.unmodifiableSortedMap(m);");
		out.println("	}");
		out.println();
		out.println("	public static <T> SortedSet<T> unmodifiableSortedSet(");
		out.println("			final SortedSet<T> s)");
		out.println("	{");
		out.println("		if(s == null)");
		out.println("			return null;");
		out.println("		return Collections.unmodifiableSortedSet(s);");
		out.println("	}");
		out.println("}");
	}
}
